package nl.rug.snitter.user;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.Index;
import javax.jdo.annotations.Indices;
import javax.jdo.annotations.NotPersistent;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

import nl.rug.snitter.message.MessageManager;
import nl.rug.snitter.message.MessagePropagation;
import nl.rug.snitter.site.SimpleUserInfo;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
@Indices({@Index(name="index_ids", members={"id"}), @Index(name="index_names", members={"name"}), @Index(name="index_emails", members={"email"})})
public class User {
	
	@PrimaryKey
	@Persistent(valueStrategy= IdGeneratorStrategy.IDENTITY)
	private Long id;
	@Persistent
	private String password;
	@Persistent
	private String name;
	@Persistent
	private String screenName;
	@Persistent
	private String adress;
	@Persistent
	private String zipCode;
	@Persistent
	private String email;
	@Persistent
	private MessageManager messageManager;
	@Persistent
	private byte[] serializedIncomingFollowRequest;
	@Persistent
	private byte[] serializedFollowing;
	@Persistent
	private byte[] serializedFollowedBy;
	@Persistent
	private byte[] serializedNewMsgFrom;
	@NotPersistent
	private ArrayList<Long> incomingFollowRequest;
	@NotPersistent
	private ArrayList<Long> following;
	@NotPersistent
	private ArrayList<Long> followedBy;
	@NotPersistent
	private HashMap<Long, Long> newMsgFrom;
	
	public User()
	{
		this.incomingFollowRequest= new ArrayList<Long>();
		this.messageManager= new MessageManager();
		this.following= new ArrayList<Long>();
		this.followedBy= new ArrayList<Long>();
		this.newMsgFrom= new HashMap<Long, Long>();
	}
	
	public User(String name, String screenName, String adress, String zipCode, String email)
	{
		this.name= name;
		this.screenName= screenName;
		this.adress= adress;
		this.zipCode= zipCode;
		this.email= email;
		this.incomingFollowRequest= new ArrayList<Long>();
		this.messageManager= new MessageManager();
		this.following= new ArrayList<Long>();
		this.followedBy= new ArrayList<Long>();
		this.newMsgFrom= new HashMap<Long, Long>();
	}
	
	public void setId(long id)
	{
		this.id = id;
	}
	
	public long getId()
	{
		return id;
	}
	
	public void setName(String name)
	{
		this.name = name;
	}
	
	public String getName()
	{
		return name;
	}
	
	public void setScreenName(String screenName)
	{
		this.screenName = screenName;
	}
	
	public String getScreenName()
	{
		return screenName;
	}
	
	public void setAdress(String adress)
	{
		this.adress = adress == null? "" : adress;
	}
	
	public String getAdress()
	{
		return adress;
	}
	
	public void setZipCode(String zipCode)
	{
		this.zipCode = zipCode == null ? "" : zipCode;
	}
	
	public String getZipCode()
	{
		return zipCode;
	}
	
	public void setEmail(String email)
	{
		this.email = email;
	}
	
	public String getEmail()
	{
		return email;
	}
	
	public void addIncomingFollowRequest(Long userId)
	{
		this.incomingFollowRequest.add(userId);
	}
	
	public List<Long> getIncomingFollowRequest()
	{
		return incomingFollowRequest;
	}

	public void setMessageManager(MessageManager messageManager)
	{
		this.messageManager = messageManager;
	}

	public MessageManager getMessageManager()
	{
		return messageManager;
	}

	public void addFollowing(Long id, MessagePropagation propagation)
	{
		this.following.add(id);
		this.messageManager.addMsgPropagation(id, propagation);
	}

	public List<Long> getFollowing()
	{
		return following;
	}

	public void addFollowedBy(Long id)
	{
		this.followedBy.add(id);
	}

	public List<Long> getFollowedBy()
	{
		return followedBy;
	}
	
	public void serializeFields() throws IOException
	{
		ObjectOutputStream out1= null;
		ObjectOutputStream out2= null;
		ObjectOutputStream out3= null;
		ObjectOutputStream out4= null;
		try
		{
			ByteArrayOutputStream bOut1= new ByteArrayOutputStream();
			ByteArrayOutputStream bOut2= new ByteArrayOutputStream();
			ByteArrayOutputStream bOut3= new ByteArrayOutputStream();
			ByteArrayOutputStream bOut4= new ByteArrayOutputStream();
			out1= new ObjectOutputStream(bOut1);
			out2= new ObjectOutputStream(bOut2);
			out3= new ObjectOutputStream(bOut3);
			out4= new ObjectOutputStream(bOut4);
			out1.writeObject(this.incomingFollowRequest);
			out2.writeObject(this.following);
			out3.writeObject(this.followedBy);
			out4.writeObject(this.newMsgFrom);
			this.serializedIncomingFollowRequest= bOut1.toByteArray();
			this.serializedFollowing= bOut2.toByteArray();
			this.serializedFollowedBy= bOut3.toByteArray();
			this.serializedNewMsgFrom= bOut4.toByteArray();
			this.messageManager.serializeFields();
		}
		finally
		{
			out1.close();
			out2.close();
			out3.close();
			out4.close();
		}
	}
	
	@SuppressWarnings("unchecked")
	public void deSerializeFields() throws IOException, ClassNotFoundException
	{
		ObjectInputStream in1= null;
		ObjectInputStream in2= null;
		ObjectInputStream in3= null;
		ObjectInputStream in4= null;
		try
		{
			ByteArrayInputStream bIn1= new ByteArrayInputStream(this.serializedIncomingFollowRequest);
			ByteArrayInputStream bIn2= new ByteArrayInputStream(this.serializedFollowing);
			ByteArrayInputStream bIn3= new ByteArrayInputStream(this.serializedFollowedBy);
			ByteArrayInputStream bIn4= new ByteArrayInputStream(this.serializedNewMsgFrom);
			in1= new ObjectInputStream(bIn1);
			in2= new ObjectInputStream(bIn2);
			in3= new ObjectInputStream(bIn3);
			in4= new ObjectInputStream(bIn4);
			this.incomingFollowRequest= (ArrayList<Long>) in1.readObject();
			this.following= (ArrayList<Long>) in2.readObject();
			this.followedBy= (ArrayList<Long>) in3.readObject();
			this.newMsgFrom= (HashMap<Long, Long>) in4.readObject();
			this.messageManager.deSerializeFields();
		}
		finally
		{
			in1.close();
			in2.close();
			in3.close();
			in4.close();
		}
	}

	public void addMsg(Long msgId)
	{
		this.messageManager.addMessage(msgId);
	}

	public void addNewMsgFrom(Long id, Long times)
	{
		if(this.newMsgFrom.containsKey(id))
		{
			long temp= this.newMsgFrom.get(id);
			temp+= times;
			this.newMsgFrom.put(id, temp);
		}
		else
		{
			this.newMsgFrom.put(id, times);
		}
	}
	
	public void removeNewMsgFrom(Long id)
	{
		if(this.newMsgFrom.containsKey(id))
		{
			this.newMsgFrom.remove(id);
		}
	}
	
	public void clearNewMsgFrom()
	{
		this.newMsgFrom.clear();
	}

	public long getNewMsgFrom(Long id)
	{
		if(this.newMsgFrom.containsKey(id))
		{
			return this.newMsgFrom.get(id);
		}
		return 0;
	}

	public void setPassword(String password)
	{
		this.password = password;
	}

	public String getPassword()
	{
		return password;
	}
	
	public SimpleUserInfo convertToSimpleUserInfo()
	{
		return new SimpleUserInfo(name, screenName, email, adress, zipCode, following, followedBy, newMsgFrom);
	}
	
}
